home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / MacHacksBug / Python 1.5.2c1 / Tools / idle / AutoIndent.py < prev    next >
Encoding:
Python Source  |  2000-06-23  |  7.6 KB  |  245 lines

  1. import string
  2. from Tkinter import TclError
  3.  
  4. ###$ event <<newline-and-indent>>
  5. ###$ win <Key-Return>
  6. ###$ win <KP_Enter>
  7. ###$ unix <Key-Return>
  8. ###$ unix <KP_Enter>
  9.  
  10. ###$ event <<indent-region>>
  11. ###$ win <Control-bracketright>
  12. ###$ unix <Alt-bracketright>
  13. ###$ unix <Control-bracketright>
  14.  
  15. ###$ event <<dedent-region>>
  16. ###$ win <Control-bracketleft>
  17. ###$ unix <Alt-bracketleft>
  18. ###$ unix <Control-bracketleft>
  19.  
  20. ###$ event <<comment-region>>
  21. ###$ win <Alt-Key-3>
  22. ###$ unix <Alt-Key-3>
  23.  
  24. ###$ event <<uncomment-region>>
  25. ###$ win <Alt-Key-4>
  26. ###$ unix <Alt-Key-4>
  27.  
  28. ###$ event <<tabify-region>>
  29. ###$ win <Alt-Key-5>
  30. ###$ unix <Alt-Key-5>
  31.  
  32. ###$ event <<untabify-region>>
  33. ###$ win <Alt-Key-6>
  34. ###$ unix <Alt-Key-6>
  35.  
  36. class AutoIndent:
  37.  
  38.     menudefs = [
  39.         ('edit', [
  40.             None,
  41.             ('_Indent region', '<<indent-region>>'),
  42.             ('_Dedent region', '<<dedent-region>>'),
  43.             ('Comment _out region', '<<comment-region>>'),
  44.             ('U_ncomment region', '<<uncomment-region>>'),
  45.             ('Tabify region', '<<tabify-region>>'),
  46.             ('Untabify region', '<<untabify-region>>'),
  47.         ]),
  48.     ]
  49.  
  50.     keydefs = {
  51.         '<<smart-backspace>>': ['<Key-BackSpace>'],
  52.         '<<newline-and-indent>>': ['<Key-Return>', '<KP_Enter>'],
  53.     }
  54.  
  55.     windows_keydefs = {
  56.         '<<indent-region>>': ['<Control-bracketright>'],
  57.         '<<dedent-region>>': ['<Control-bracketleft>'],
  58.         '<<comment-region>>': ['<Alt-Key-3>'],
  59.         '<<uncomment-region>>': ['<Alt-Key-4>'],
  60.         '<<tabify-region>>': ['<Alt-Key-5>'],
  61.         '<<untabify-region>>': ['<Alt-Key-6>'],
  62.     }
  63.  
  64.     unix_keydefs = {
  65.         '<<indent-region>>': ['<Alt-bracketright>',
  66.                               '<Meta-bracketright>',
  67.                               '<Control-bracketright>'],
  68.         '<<dedent-region>>': ['<Alt-bracketleft>',
  69.                               '<Meta-bracketleft>',
  70.                               '<Control-bracketleft>'],
  71.         '<<comment-region>>': ['<Alt-Key-3>', '<Meta-Key-3>'],
  72.         '<<uncomment-region>>': ['<Alt-Key-4>', '<Meta-Key-4>'],
  73.         '<<tabify-region>>': ['<Alt-Key-5>', '<Meta-Key-5>'],
  74.         '<<untabify-region>>': ['<Alt-Key-6>', '<Meta-Key-6>'],
  75.     }
  76.  
  77.     prefertabs = 0
  78.     spaceindent = 4*" "
  79.  
  80.     def __init__(self, editwin):
  81.         self.text = editwin.text
  82.  
  83.     def config(self, **options):
  84.         for key, value in options.items():
  85.             if key == 'prefertabs':
  86.                 self.prefertabs = value
  87.             elif key == 'spaceindent':
  88.                 self.spaceindent = value
  89.             else:
  90.                 raise KeyError, "bad option name: %s" % `key`
  91.  
  92.     def smart_backspace_event(self, event):
  93.         text = self.text
  94.         try:
  95.             first = text.index("sel.first")
  96.             last = text.index("sel.last")
  97.         except TclError:
  98.             first = last = None
  99.         if first and last:
  100.             text.delete(first, last)
  101.             text.mark_set("insert", first)
  102.             return "break"
  103.         # After Tim Peters
  104.         ndelete = 1
  105.         chars = text.get("insert linestart", "insert")
  106.         i = 0
  107.         n = len(chars)
  108.         while i < n and chars[i] in " \t":
  109.             i = i+1
  110.         if i == n and chars[-4:] == "    ":
  111.             ndelete = 4
  112.         text.delete("insert - %d chars" % ndelete, "insert")
  113.         return "break"
  114.  
  115.     def newline_and_indent_event(self, event):
  116.         text = self.text
  117.         try:
  118.             first = text.index("sel.first")
  119.             last = text.index("sel.last")
  120.         except TclError:
  121.             first = last = None
  122.         if first and last:
  123.             text.delete(first, last)
  124.             text.mark_set("insert", first)
  125.         line = text.get("insert linestart", "insert")
  126.         i, n = 0, len(line)
  127.         while i < n and line[i] in " \t":
  128.             i = i+1
  129.         indent = line[:i]
  130.         lastchar = text.get("insert -1c")
  131.         if lastchar == ":":
  132.             if not indent:
  133.                 if self.prefertabs:
  134.                     indent = "\t"
  135.                 else:
  136.                     indent = self.spaceindent
  137.             elif indent[-1] == "\t":
  138.                 indent = indent + "\t"
  139.             else:
  140.                 indent = indent + self.spaceindent
  141.         text.insert("insert", "\n" + indent)
  142.         text.see("insert")
  143.         return "break"
  144.  
  145.     auto_indent = newline_and_indent_event
  146.  
  147.     def indent_region_event(self, event):
  148.         head, tail, chars, lines = self.get_region()
  149.         for pos in range(len(lines)):
  150.             line = lines[pos]
  151.             if line:
  152.                 i, n = 0, len(line)
  153.                 while i < n and line[i] in " \t":
  154.                     i = i+1
  155.                 line = line[:i] + "    " + line[i:]
  156.                 lines[pos] = line
  157.         self.set_region(head, tail, chars, lines)
  158.         return "break"
  159.  
  160.     def dedent_region_event(self, event):
  161.         head, tail, chars, lines = self.get_region()
  162.         for pos in range(len(lines)):
  163.             line = lines[pos]
  164.             if line:
  165.                 i, n = 0, len(line)
  166.                 while i < n and line[i] in " \t":
  167.                     i = i+1
  168.                 indent, line = line[:i], line[i:]
  169.                 if indent:
  170.                     if indent == "\t" or indent[-2:] == "\t\t":
  171.                         indent = indent[:-1] + "    "
  172.                     elif indent[-4:] == "    ":
  173.                         indent = indent[:-4]
  174.                     else:
  175.                         indent = string.expandtabs(indent, 8)
  176.                         indent = indent[:-4]
  177.                     line = indent + line
  178.                 lines[pos] = line
  179.         self.set_region(head, tail, chars, lines)
  180.         return "break"
  181.  
  182.     def comment_region_event(self, event):
  183.         head, tail, chars, lines = self.get_region()
  184.         for pos in range(len(lines)):
  185.             line = lines[pos]
  186.             if not line:
  187.                 continue
  188.             lines[pos] = '##' + line
  189.         self.set_region(head, tail, chars, lines)
  190.  
  191.     def uncomment_region_event(self, event):
  192.         head, tail, chars, lines = self.get_region()
  193.         for pos in range(len(lines)):
  194.             line = lines[pos]
  195.             if not line:
  196.                 continue
  197.             if line[:2] == '##':
  198.                 line = line[2:]
  199.             elif line[:1] == '#':
  200.                 line = line[1:]
  201.             lines[pos] = line
  202.         self.set_region(head, tail, chars, lines)
  203.  
  204.     def tabify_region_event(self, event):
  205.         head, tail, chars, lines = self.get_region()
  206.         lines = map(tabify, lines)
  207.         self.set_region(head, tail, chars, lines)
  208.  
  209.     def untabify_region_event(self, event):
  210.         head, tail, chars, lines = self.get_region()
  211.         lines = map(string.expandtabs, lines)
  212.         self.set_region(head, tail, chars, lines)
  213.  
  214.     def get_region(self):
  215.         text = self.text
  216.         head = text.index("sel.first linestart")
  217.         tail = text.index("sel.last -1c lineend +1c")
  218.         if not (head and tail):
  219.             head = text.index("insert linestart")
  220.             tail = text.index("insert lineend +1c")
  221.         chars = text.get(head, tail)
  222.         lines = string.split(chars, "\n")
  223.         return head, tail, chars, lines
  224.  
  225.     def set_region(self, head, tail, chars, lines):
  226.         text = self.text
  227.         newchars = string.join(lines, "\n")
  228.         if newchars == chars:
  229.             text.bell()
  230.             return
  231.         text.tag_remove("sel", "1.0", "end")
  232.         text.mark_set("insert", head)
  233.         text.delete(head, tail)
  234.         text.insert(head, newchars)
  235.         text.tag_add("sel", head, "insert")
  236.  
  237. def tabify(line, tabsize=8):
  238.     spaces = tabsize * ' '
  239.     for i in range(0, len(line), tabsize):
  240.         if line[i:i+tabsize] != spaces:
  241.             break
  242.     else:
  243.         i = len(line)
  244.     return '\t' * (i/tabsize) + line[i:]
  245.